pub use crate::contract::coolink_sdk::SDKApiResult;
pub type Result<T> = std::result::Result<T, anyhow::Error>;

use std::fmt::Display;
use thiserror::Error;

// default request connection timeout seconds
pub const DEFAULT_CONNECTION_TIMEOUT_SECS: u64 = 5;
// default request timeout seconds
pub const DEFAULT_REQUEST_TIMEOUT_SECS: u64 = 10;
// default websocket handshake timeout seconds
pub const DEFAULT_REQUEST_TIMEOUT_WS_HANDSHAKE: u64 = 5;

// default success code
pub const REQ_SUCCESS: i64 = 0;

/// Sdk custome error
/// anyhow::Error may be downcast to this
#[derive(Error, Debug)]
pub enum SDKResultError {
    #[error("Client Need Call Link Sdk Init First!")]
    ErrorLinkSdkNotInited, // -40001
    #[error("Client Already Connected!")]
    ErrorAlreadyConnected, // 40002 , > 0 errro means not need retry.
    #[error("Client Need Alternative Host!")]
    ErrorHostNeedAlternative, //-40003
    #[error("Client Runtime Error!")]
    ErrorRuntime, // -40004
    #[error("Server Check Authentication Failed,Please Check!")]
    ErrorAuthentication, // -40005
    #[error("Client Connect Droped!")]
    ErrorNotConnected, // -40006
    #[error("Client Source ID Not Found!")]
    ErrorNotClientSourceIDFound, // -40007
    #[error("Client Alerady Async Connected!")]
    ErrorAsyncAlreadyConnected, // 40008, > 0 errro means not need retry.
    #[error("Client Send Channel Broken!")]
    ErrorSendChannelBroken, // -40009
    #[error("Client Send Server Ack Timeout!")]
    ErrorSendServerAckTimeout, // -40010
    #[error("Client Send Server Err Ack!")]
    ErrorSendServerReturnErr, // -40011
    #[error("Client Start Tonic Already Started!")]
    ErrorTonicServerAlreadyStarted, // 40012 > 0 errro means not need retry.
    #[error("Client Need Call Rtm Sdk Init First!")]
    ErrorRtmSdkNotInited, // -40013
    #[error("Client Not Tonic Server Started!")]
    ErrorNoTonicServerStarted, // -40014
    #[error("Client Connect Tonic Tunnel Error!")]
    ErrorSyncConnectTonicTunnel, // -40015
    #[error("Client Already Connect Tonic Tunnel With Same TunnelID!")]
    ErrorAlreadyConnectTonicTunnelID, // 40016 >0 errro means not need retry.
    #[error("Client Close Tonic Tunnel Channel Broken Error!")]
    ErrorTonicTunnelChannelBroken, // -40017
    #[error("Client Close Tonic Tunnel Not Found Tunnel ID!")]
    ErrorNotFoundTonicTunnelID, // -40018
    #[error("Client Not Http Server Started!")]
    ErrorNotHttpSrvStarted, // -40019
    #[error("Client Start Http Srv Already Started!")]
    ErrorHttpSrvAlreadyStarted, // 40020 > 0 errro means not need retry.
    #[error("Client Websocket Handshake Timeout!")]
    ErrorWsHandshakeTimeout, //-40021
    #[error("Client Get Lan Host Json Decode Error!")]
    ErrorGetLanHostJsonError, //-40022
}

// from anyhow::Error
impl From<anyhow::Error> for SDKApiResult {
    fn from(err: anyhow::Error) -> Self {
        match err.downcast::<SDKApiResult>() {
            Ok(err) => err,
            Err(err) => {
                let cc_error = err.downcast_ref::<SDKResultError>();
                if let Some(err) = cc_error {
                    match err {
                        SDKResultError::ErrorLinkSdkNotInited => SDKApiResult::error_code_string(
                            -40001,
                            SDKResultError::ErrorLinkSdkNotInited.to_string(),
                        ),
                        SDKResultError::ErrorAlreadyConnected => SDKApiResult::error_code_string(
                            40002,
                            SDKResultError::ErrorAlreadyConnected.to_string(),
                        ),
                        SDKResultError::ErrorHostNeedAlternative => {
                            SDKApiResult::error_code_string(
                                -40003,
                                SDKResultError::ErrorHostNeedAlternative.to_string(),
                            )
                        }
                        SDKResultError::ErrorRuntime => SDKApiResult::error_code_string(
                            -40004,
                            SDKResultError::ErrorRuntime.to_string(),
                        ),
                        SDKResultError::ErrorAuthentication => SDKApiResult::error_code_string(
                            -40005,
                            SDKResultError::ErrorAuthentication.to_string(),
                        ),
                        SDKResultError::ErrorNotConnected => SDKApiResult::error_code_string(
                            -40006,
                            SDKResultError::ErrorNotConnected.to_string(),
                        ),
                        SDKResultError::ErrorNotClientSourceIDFound => {
                            SDKApiResult::error_code_string(
                                -40007,
                                SDKResultError::ErrorNotClientSourceIDFound.to_string(),
                            )
                        }
                        SDKResultError::ErrorAsyncAlreadyConnected => {
                            SDKApiResult::error_code_string(
                                40008,
                                SDKResultError::ErrorAsyncAlreadyConnected.to_string(),
                            )
                        }
                        SDKResultError::ErrorSendChannelBroken => SDKApiResult::error_code_string(
                            -40009,
                            SDKResultError::ErrorSendChannelBroken.to_string(),
                        ),
                        SDKResultError::ErrorSendServerAckTimeout => {
                            SDKApiResult::error_code_string(
                                -40010,
                                SDKResultError::ErrorSendServerAckTimeout.to_string(),
                            )
                        }
                        SDKResultError::ErrorSendServerReturnErr => {
                            SDKApiResult::error_code_string(
                                -40011,
                                SDKResultError::ErrorSendServerReturnErr.to_string(),
                            )
                        }
                        SDKResultError::ErrorTonicServerAlreadyStarted => {
                            SDKApiResult::error_code_string(
                                40012,
                                SDKResultError::ErrorTonicServerAlreadyStarted.to_string(),
                            )
                        }
                        SDKResultError::ErrorRtmSdkNotInited => SDKApiResult::error_code_string(
                            -40013,
                            SDKResultError::ErrorRtmSdkNotInited.to_string(),
                        ),
                        SDKResultError::ErrorNoTonicServerStarted => {
                            SDKApiResult::error_code_string(
                                -40014,
                                SDKResultError::ErrorNoTonicServerStarted.to_string(),
                            )
                        }
                        SDKResultError::ErrorSyncConnectTonicTunnel => {
                            SDKApiResult::error_code_string(
                                -40015,
                                SDKResultError::ErrorSyncConnectTonicTunnel.to_string(),
                            )
                        }
                        SDKResultError::ErrorAlreadyConnectTonicTunnelID => {
                            SDKApiResult::error_code_string(
                                40016,
                                SDKResultError::ErrorAlreadyConnectTonicTunnelID.to_string(),
                            )
                        }
                        SDKResultError::ErrorTonicTunnelChannelBroken => {
                            SDKApiResult::error_code_string(
                                -40017,
                                SDKResultError::ErrorTonicTunnelChannelBroken.to_string(),
                            )
                        }
                        SDKResultError::ErrorNotFoundTonicTunnelID => {
                            SDKApiResult::error_code_string(
                                -40018,
                                SDKResultError::ErrorNotFoundTonicTunnelID.to_string(),
                            )
                        }
                        SDKResultError::ErrorNotHttpSrvStarted => SDKApiResult::error_code_string(
                            -40019,
                            SDKResultError::ErrorNotHttpSrvStarted.to_string(),
                        ),
                        SDKResultError::ErrorHttpSrvAlreadyStarted => {
                            SDKApiResult::error_code_string(
                                40020,
                                SDKResultError::ErrorHttpSrvAlreadyStarted.to_string(),
                            )
                        }
                        SDKResultError::ErrorWsHandshakeTimeout => SDKApiResult::error_code_string(
                            -40021,
                            SDKResultError::ErrorWsHandshakeTimeout.to_string(),
                        ),
                        SDKResultError::ErrorGetLanHostJsonError => {
                            SDKApiResult::error_code_string(
                                -40022,
                                SDKResultError::ErrorGetLanHostJsonError.to_string(),
                            )
                        }
                    }
                } else {
                    SDKApiResult::error_string(err.to_string())
                }
            }
        }
    }
}

impl From<Result<()>> for SDKApiResult {
    fn from(res: Result<()>) -> Self {
        match res {
            Ok(()) => SDKApiResult::ok(),
            Err(err) => err.into(),
        }
    }
}
impl From<Result<String>> for SDKApiResult {
    fn from(res: Result<String>) -> Self {
        match res {
            Ok(msg) => SDKApiResult::msg(msg),
            Err(err) => err.into(),
        }
    }
}

impl SDKApiResult {
    fn error_with_code(code: i64) -> Self {
        SDKApiResult {
            code,
            msg: "".to_owned(),
        }
    }

    fn error_code_str(code: i64, msg_str: &str) -> Self {
        SDKApiResult {
            code,
            msg: msg_str.to_owned(),
        }
    }
    pub fn error_str(msg_str: &str) -> Self {
        SDKApiResult {
            code: -1,
            msg: msg_str.to_owned(),
        }
    }
    pub fn error_string(msg: String) -> Self {
        SDKApiResult { code: -1, msg }
    }
    fn error_code_string(code: i64, msg: String) -> Self {
        SDKApiResult { code, msg }
    }
    pub fn ok() -> Self {
        SDKApiResult {
            code: 0,
            msg: "".to_owned(),
        }
    }
    pub fn msg(msg: String) -> Self {
        SDKApiResult { code: 0, msg }
    }
}

impl Display for SDKApiResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!(
            "SDKApiResult code: {}, msg: {}",
            self.code, self.msg
        ))
    }
}
